package me.zhengjie.controller;

import me.zhengjie.annotation.AnonymousAccess;
import me.zhengjie.common.DlaServerConfig;
import me.zhengjie.result.PrestoQueryResult;
import io.prestosql.client.ClientException;
import me.zhengjie.service.PrestoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import static me.zhengjie.util.AccessControlUtil.sendForbiddenError;
import static me.zhengjie.util.HttpRequestUtil.getRequiredParameter;
import static me.zhengjie.util.JsonUtil.writeJSON;
import static java.lang.String.format;

/**
 * 根据查询条件查到结果
 */
@RestController
public class PrestoAsyncController {
    private static final Logger LOG = LoggerFactory.getLogger(PrestoAsyncController.class);

    @Resource
    private PrestoService prestoService;
    @Resource
    private DlaServerConfig config;

    @PostMapping("prestoAsync")
    @AnonymousAccess
    public void prestoAsync(HttpServletRequest request, HttpServletResponse response)  {
        Map<String, Object> responseBody = new HashMap<>();
        String query = request.getParameter("query");
        if (query == null) {
            writeJSON(response, responseBody);
            return;
        }
        try {
            String user = getUsername(request);
            Optional<String> prestoUser = Optional.ofNullable(request.getParameter("user"));
            Optional<String> prestoPassword = Optional.ofNullable(request.getParameter("password"));
            if (config.isUserRequired() && user == null) {
                sendForbiddenError(response);
                return;
            }
            String dataSource = getRequiredParameter(request, "dataSource");
            if (user != null) {
                LOG.info(format("%s executed %s in %s", user, query, dataSource));
            }
            if (prestoUser.isPresent() && prestoPassword.isPresent() && prestoUser.get().isEmpty()) {
                responseBody.put("error", "user is empty");
                writeJSON(response, responseBody);
                return;
            }
            try {
                PrestoQueryResult result = executeQuery(dataSource, query, user, prestoUser, prestoPassword);
                responseBody.put("result", result);
            } catch (ClientException e) {
                if (prestoUser.isPresent()) {
                    LOG.error(format("%s failed to be authenticated", prestoUser.get()));
                }
                LOG.error(e.getMessage(), e);
                responseBody.put("error", e.getMessage());
            } catch (Throwable e) {
                LOG.error(e.getMessage(), e);
                responseBody.put("error", e.getMessage());
            }
        } catch (Throwable e) {
            LOG.error(e.getMessage(), e);
            responseBody.put("error", e.getMessage());
        }
        writeJSON(response, responseBody);
    }

    private PrestoQueryResult executeQuery(String dataSource, String query, String user, Optional<String> prestoUser, Optional<String> prestoPassword) {
        return prestoService.doQueryAsync(dataSource, query, user, prestoUser, prestoPassword);
    }

    private String getUsername(HttpServletRequest request) {
        if (config.isUseAuditHttpHeaderName()) {
            return request.getHeader(config.getAuditHttpHeaderName());
        }
        String user = request.getParameter("user");
        String password = request.getParameter("password");
        if (user != null && password != null) {
            return user;
        }
        return null;
    }
}
